/*
 * JFFS2 -- Journalling Flash File System, Version 2.
 *
 * Copyright (C) 2001-2003 Red Hat, Inc.
 *
 * Created by David Woodhouse <dwmw2@redhat.com>
 *
 * For licensing information, see the file 'LICENCE' in this directory.
 *
 * $Id: gcthread.c,v 1.3 2005/01/22 16:01:12 lunn Exp $
 *
 */
#include <linux/kernel.h>
#include "nodelist.h"
#include "porting.h"
#include "stdio.h"

#if defined(JFFS2OPT_FS_JFFS2_GCTHREAD)

#define GC_THREAD_FLAG_TRIG 1
#define GC_THREAD_FLAG_STOP 2
#define GC_THREAD_FLAG_HAS_EXIT 4

#endif

unsigned int jffs2_current_time(void)
{
    return 0;
}

static void
jffs2_garbage_collect_thread(unsigned long data);

//EVENT_CB_S *p_event = NULL;
void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
{
     struct super_block *sb=OFNI_BS_2SFFJ(c);

     /* Wake up the thread */
     D1(printk("jffs2_garbage_collect_trigger\n"));
        //p_event = &sb->s_gc_thread_flags;
     jffs_event_send(&sb->s_gc_thread_flags, GC_THREAD_FLAG_TRIG); /*lint !e413 !e613*/

}




//
/*lint -e413*/
void
jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
{
     struct super_block *sb=OFNI_BS_2SFFJ(c);
     jffs2_mtab_entry *s_root = (jffs2_mtab_entry *)NULL;
     TSK_INIT_PARAM_S stGcTask;

     if(c ==NULL)
        return;

     s_root=(jffs2_mtab_entry *)((jffs2_dir *)sb->s_root);
     if(s_root == NULL)
        return;

     jffs_event_create(&sb->s_gc_thread_flags);
     jffs_mutex_create(&sb->s_lock);

     D1(printk("jffs2_start_garbage_collect_thread\n"));
     /* Start the thread. Doesn't matter if it fails -- it's only an
      * optimisation anyway */
    (void)memset_s(&stGcTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));

    stGcTask.pfnTaskEntry = (TSK_ENTRY_FUNC)jffs2_garbage_collect_thread;
    stGcTask.auwArgs[0] = (AARCHPTR)c;
    stGcTask.uwStackSize  = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
    stGcTask.pcName = "jffs2_gc_thread";
    stGcTask.usTaskPrio = JFFS2NUM_JFFS2_GC_THREAD_PRIORITY;

    if (LOS_TaskCreate(&sb->s_gc_thread, &stGcTask))
        PRINT_ERR("Create gc task failed!!!\n");
}
/*lint +e413*/
/*lint -e413*/
void
jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c)
{
     struct super_block *sb=OFNI_BS_2SFFJ(c);

     D1(printk("jffs2_stop_garbage_collect_thread\n"));
     /* Stop the thread and wait for it if necessary */

     jffs_event_send(&sb->s_gc_thread_flags,GC_THREAD_FLAG_STOP);

     D1(printk("jffs2_stop_garbage_collect_thread wait\n"));

     (void)jffs_event_recv(&sb->s_gc_thread_flags,
                    GC_THREAD_FLAG_HAS_EXIT,
                    LOS_WAITMODE_OR | LOS_WAITMODE_CLR,
                    LOS_WAIT_FOREVER);

     // Kill and free the resources ...  this is safe due to the flag
     // from the thread.
     (void)LOS_TaskDelete(sb->s_gc_thread);
     jffs_mutex_delete(&sb->s_lock);
     jffs_event_detach(&sb->s_gc_thread_flags);
}
/*lint +e413*/

//
 static void
jffs2_garbage_collect_thread(unsigned long data)
{
     struct jffs2_sb_info *c=(struct jffs2_sb_info *)data;
     struct super_block *sb=OFNI_BS_2SFFJ(c);
     unsigned int flag = 0;
     jffs2_mtab_entry *s_root = (jffs2_mtab_entry *)NULL;
     int ret;

     D1(printk("jffs2_garbage_collect_thread START\n"));
     while(1) {
          flag=jffs_event_recv(&sb->s_gc_thread_flags,
                        GC_THREAD_FLAG_TRIG | GC_THREAD_FLAG_STOP,
                        LOS_WAITMODE_OR | LOS_WAITMODE_CLR,
                        LOS_WAIT_FOREVER
                         //jffs2_current_time() + JFFS2NUM_JFFS2_GS_THREAD_TICKS
                        );
          if (flag & GC_THREAD_FLAG_STOP)
               break;

          D1(printk("jffs2: GC THREAD GC BEGIN\n"));

          s_root=(jffs2_mtab_entry *)((jffs2_dir *)sb->s_root);
          if(s_root == NULL)
            return;
          ret = jffs2_garbage_collect_pass(c);
          if (ret == -ENOSPC) {
               PRINTK("No space for garbage collection. "
                      "Aborting JFFS2 GC thread\n");
               break;
          }
          D1(printk("jffs2: GC THREAD GC END\n"));
     }
     D1(printk("jffs2_garbage_collect_thread EXIT\n"));
     jffs_event_send(&sb->s_gc_thread_flags,GC_THREAD_FLAG_HAS_EXIT);
}

